﻿
namespace Octopus.OctopusLib

open System.Xml



type UserMessage (id:int, recipient:string, date:System.DateTime, text:string) =
  member x.ID = id
  member x.Recipient = recipient
  member x.Date = date
  member x.Message = text
  
  member x.Serialize() =
    sprintf "%s %s %s %s" (x.ID.ToString()) x.Recipient (x.Date.ToFileTime().ToString()) x.Message
  static member Deserialize(str:string) =
    let sa = str.Split([|' '|], 4)
    let id = System.Int32.Parse(sa.[0])
    let date = System.DateTime.FromFileTime( System.Int64.Parse(sa.[2]) )
    new UserMessage( id, sa.[1], date, sa.[3] )



type OctopusVmState =
| Normal = 0
| GenericError = 1
| ScheduledForCreation = 10
| ScheduledForConfiguring = 15
| Configuring = 16
| CreationFailed = 19
| ScheduledForDeletion = 20
| Deleting = 21
| DeletionFailed = 22
| Deleted = 23
| ScheduledForMigration = 30
| Migrating = 31
| MigrationFailed = 32 
| ScheduledForCheckpoint = 40
| Checkpointing = 41
| CheckpointFailed = 42 

type HyperVState =
| Unknown = 0
| Other = 1             // this value is never set
| Running = 2
| Stopped = 3
| Paused = 32768
| Suspended = 32769
| Starting = 32770
| Snapshotting = 32771  // Starting with Windows Server 2008 R2 this value is not supported
| Saving = 32773
| Stopping = 32774
| Pausing = 32776
| Resuming = 32777

type HyperVHealthState =
| Unknown = 0
| OK = 5
| MajorFailure = 20     // This value is not supported before Windows Server 2008 R2.
| CriticalFailure = 25
// these states are octopus-defined, not in Hyper-V
| Unreachable = 5555
| HostUnreachable = 5556

type HyperVHeartbeat =
| Unknown = 0
| OK = 2
| Error = 6
| NoContact = 12
| LostCommunication = 13


type VirtualMachineRequested
  (octopusGuid:System.Guid, numberOfVm:uint16, ownername:string, hostname:string,
   cpuCount:uint16, memorySize:uint64, vmTemplateID:int32, password:string) =

  member x.OctopusGuid = octopusGuid
  member x.NumberOfVm = numberOfVm
  member x.OwnerName = ownername
  member x.HostName = hostname
  member x.CpuCount = cpuCount
  member x.MemorySize = memorySize
  member x.VmTemplateID = vmTemplateID
  member x.Password = password



type VirtualMachineData 
  (octopusGuid:System.Guid, cpuCount:uint16, memorySize:uint64,
   octopusState:OctopusVmState, owner:string, hostname:string,
   macAddress:string, vmTemplateID:int32) =

  member x.OctopusGuid = octopusGuid
  member x.CpuCount = cpuCount
  member x.MemorySize = memorySize
  member x.OctopusState = octopusState
  member x.OwnerName = owner
  member x.HostName = hostname
  member x.MacAddress = macAddress
  member x.VmTemplateID = vmTemplateID

  abstract member Serialize : unit -> string

  default x.Serialize () =
      let res = [| x.OctopusGuid.ToString(); string x.CpuCount;
                   string x.MemorySize; string (int x.OctopusState); x.OwnerName;
                   x.HostName; x.MacAddress; string x.VmTemplateID |]
      Utility.ObjSerializer.serialize res
  static member Deserialize (str:string) =
      let res = (Utility.ObjSerializer.deserialize str) :?> string array
      let guid = new System.Guid( res.[0] )
      let cpucount = System.UInt16.Parse( res.[1] )
      let memorysize = System.UInt64.Parse( res.[2] )
      let octopusstate = enum<OctopusVmState> (System.Int32.Parse( res.[3] ))
      let ownername = res.[4]
      let hostname = res.[5]
      let macaddress = res.[6]
      let vmtemplateid = System.Int32.Parse( res.[7] )
      let password = res.[8]
      new VirtualMachineData(guid,cpucount,memorysize,octopusstate,ownername,hostname,macaddress,vmtemplateid)



type VirtualMachinePendingCreation
  (guid:System.Guid, cpuCount:uint16, memorySize:uint64,
   octopusState:OctopusVmState, owner:string, hostname:string,
   macAddress:string, vmTemplateID:int32, hostServer:string, password:string) =

  inherit VirtualMachineData(guid,cpuCount,memorySize,octopusState,owner,hostname,macAddress,vmTemplateID)

  new (vmd:VirtualMachineData, hostServer, password) =
      new VirtualMachinePendingCreation(vmd.OctopusGuid, vmd.CpuCount, vmd.MemorySize, vmd.OctopusState, vmd.OwnerName, vmd.HostName, vmd.MacAddress, vmd.VmTemplateID, hostServer, password)
  
  member x.HostServer = hostServer
  member x.Password = password

  override x.Serialize () = failwith "You cannot serialize VirtualMachinePendingCreation"




type VirtualMachine
  (octopusGuid:System.Guid, hypervGuid:System.Guid, cpuCount:uint16, memorySize:uint64, server:string,
   storedPath:string, hypervState:HyperVState, healthState:HyperVHealthState,
   heartbeat:HyperVHeartbeat, octopusState:OctopusVmState, hpcState:int32,
   lastStatesCheck:System.DateTime, isCheckpointed:bool, owner:string, hostname:string,
   macAddress:string, ipv4Address:System.Net.IPAddress, vmTemplateID:int32) =
   
  inherit VirtualMachineData(octopusGuid,cpuCount,memorySize,octopusState,owner,hostname,macAddress,vmTemplateID)

  new (vmd:VirtualMachineData, hypervGuid:System.Guid, octopusState, hypervState, healthState, heartbeat, hpcState,
       lastStatesCheck, server, storedPath, isCheckpointed, ipv4Address) =
      new VirtualMachine(vmd.OctopusGuid, hypervGuid, vmd.CpuCount, vmd.MemorySize, server, storedPath, hypervState, healthState, heartbeat, octopusState, hpcState, lastStatesCheck, isCheckpointed, vmd.OwnerName, vmd.HostName, vmd.MacAddress, ipv4Address, vmd.VmTemplateID)
  
  member x.HyperVGuid = hypervGuid
  member x.HyperVState = hypervState
  member x.HyperVHealthState = healthState
  member x.HyperVHeartbeat = heartbeat
  member x.HpcState = hpcState

  member x.LastStatesCheck = lastStatesCheck

  member x.CurrentServer = server
  member x.StoredPath = storedPath
  member x.IsCheckpointed = isCheckpointed
  member x.Ipv4Address = ipv4Address
  

  override x.Serialize () =
      let res = [| string x.OctopusGuid; string x.HyperVGuid; string x.CpuCount;
                   string x.MemorySize; x.CurrentServer; x.StoredPath;
                   string (int x.HyperVState); string (int x.HyperVHealthState);
                   string (int x.HyperVHeartbeat); string (int x.OctopusState);
                   string hpcState; string (x.LastStatesCheck.ToBinary());
                   string (x.IsCheckpointed); x.OwnerName; x.HostName;
                   x.MacAddress; string x.Ipv4Address; string x.VmTemplateID |]
      Utility.ObjSerializer.serialize res
  static member Deserialize (str:string) =
      let res = (Utility.ObjSerializer.deserialize str) :?> string array
      let octopusGuid = new System.Guid( res.[0] )
      let hypervGuid = new System.Guid( res.[1] )
      let cpucount = System.UInt16.Parse( res.[2] )
      let memorysize = System.UInt64.Parse( res.[3] )
      let currentserver = res.[4]
      let storedpath = res.[5]
      let hypervstate = enum<HyperVState> (System.Int32.Parse( res.[6] ))
      let hypervhealthstate = enum<HyperVHealthState> (System.Int32.Parse( res.[7] ))
      let hypervheartbeat = enum<HyperVHeartbeat> (System.Int32.Parse( res.[8] ))
      let octopusstate = enum<OctopusVmState> (System.Int32.Parse( res.[9] ))
      let hpcstate = System.Int32.Parse( res.[10] )
      let laststatecheck = System.DateTime.FromBinary( System.Int64.Parse(res.[11]) )
      let ischeckpointed = System.Boolean.Parse( res.[12] )
      let ownername = res.[13]
      let hostname = res.[14]
      let macaddress = res.[15]
      let ipv4address = System.Net.IPAddress.Parse( res.[16] )
      let vmtemplateid = System.Int32.Parse( res.[17] )
      new VirtualMachine(octopusGuid,hypervGuid,cpucount,memorysize,currentserver,storedpath,hypervstate,hypervhealthstate,hypervheartbeat,octopusstate,hpcstate,laststatecheck,ischeckpointed,ownername,hostname,macaddress,ipv4address,vmtemplateid)



type VMTemplate
  (id:int, name:string, description:string, cpuCoresMin:uint16, cpuCoresMax:uint16,
   memorySizeMbMin:int, memorySizeMbMax:int, nicName:string, vhdPath:string, parentTemplateID:int,
   isHpcNode:bool, hpcScheduler:string) =
  
  member x.ID = id
  member x.Name = name
  member x.Description = description
  member x.CpuCoresMin = cpuCoresMin
  member x.CpuCoresMax = cpuCoresMax
  member x.MemorySizeMbMin = memorySizeMbMin
  member x.MemorySizeMbMax = memorySizeMbMax
  member x.NicSwitchName = nicName
  member x.VhdPath = vhdPath
  member x.ParentTemplateID = parentTemplateID
  
  member x.IsHpcNode = isHpcNode
  member x.HpcScheduler = hpcScheduler

  member x.Serialize () =
      let res = [| string x.ID; x.Name; x.Description; string x.CpuCoresMin;
                   string x.CpuCoresMax; string x.MemorySizeMbMin;
                   string x.MemorySizeMbMax; nicName; x.VhdPath; string x.ParentTemplateID;
                   string x.IsHpcNode; x.HpcScheduler |]
      Utility.ObjSerializer.serialize res
  static member Deserialize (str:string) =
      let res = (Utility.ObjSerializer.deserialize str) :?> string array
      let id = System.Int32.Parse( res.[0] )
      let name = res.[1]
      let description = res.[2]
      let cpucountmin = System.UInt16.Parse( res.[3] )
      let cpucountmax = System.UInt16.Parse( res.[4] )
      let memorysizemin = System.Int32.Parse( res.[5] )
      let memorysizemax = System.Int32.Parse( res.[6] )
      let nicname = res.[7]
      let vhdpath = res.[8]
      let parenttemplateid = System.Int32.Parse( res.[9] )
      let ishpcnode = System.Boolean.Parse( res.[10] )
      let hpcscheduler = res.[11]
      new VMTemplate(id,name,description,cpucountmin,cpucountmax,memorysizemin,memorysizemax,nicname,vhdpath,parenttemplateid,ishpcnode,hpcscheduler)
